#include <windows.h>
//#include <Pkfuncs.h>
#include <ceddk.h>

//#include "SianoSPI.h"
#include "BusDrvIf.h"
//#include "SpiHw.h"

#include "SianoSPI.h"
#include "smsspiphy.h"

//define MEASURE_PERFORMANCE

/************************************************************************
*                                                                      *
* FILE NAME:   SianoSPI.cpp	                                       *
*                                                                      *
* DESCRIPTION:														   *
*									                                   *
*                                                                      *
* Copyright (C) 2006 Consonance Ltd.	                               *
* All rights reserved                                                  *
*                                                                      *
************************************************************************/


DBGPARAM dpCurSettings = {
    TEXT("BUILTINTEST"), {
    TEXT("Errors"),    TEXT("Warnings"),  TEXT("Init"),        TEXT("Trace"),
    TEXT("SPI_INIT"),  TEXT("SPI_READ"),  TEXT("SPI_WRITE"),   TEXT("SPI_IOCTL"),
	TEXT("SPI_DEINIT"), TEXT("ZONE_FUNCTION"), TEXT("Undefined"), TEXT("Undefined")
    },
     ZONE_ERROR_SET //| ZONE_WARNING_SET | ZONE_INIT_SET | ZONE_INFO_SET //| ZONE_DETAILED_SET
};


static CHAR preamble_pattern[] = { 0xa5, 0x5a, 0xe7, 0x7e };

#define RX_BUF_SIZE	0x1200
#define TX_BUF_SIZE	0x200

#define MAX_REG_PATH_SIZE 100
#define MAX_REG_KEY_SIZE 100


#define WAIT_FOR_DRIVER_LOADING_TIME 5000//waiting to be able to read from reg
#ifdef USE_CONSO_DEFAULT 
//if we are on test mode use the SPI path if it is release use BuiltIn...
#define REG_PATH L"Drivers\\SPI\\SianoSPI"
#else
#define REG_PATH L"Drivers\\BuiltIn\\SianoSPI"
#endif


#define MAX_MNPRT_NAME 64
#define DRIVERLOADING 2000
//RAN: for debug purpose
extern DWORD gt_Freq;//frequency of the Performance Counter declared in SpiHw.cpp.
DWORD gt_ClntST;
DWORD gt_ClntET;
LARGE_INTEGER Li_Clnt;
//#define POSTDEBUGMSG
DWORD g_RecievedBytes;



static void MsgFound(void* context, void* buf, int offset, int len)
{	
	PSPIDEVICEEXTENSION pSpiDevExt = context;
	DBGMSG(ZONE_INFO, (TEXT("SmsSpi: MsgFound().\r\n")));
	if (pSpiDevExt->pBD_ReadCBFunc)
	{
		DBGMSG(ZONE_INFO, (TEXT("SmsSpi: Calling back with message at offset %d: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, \r\n"),
																								offset, 
																					(char*)((char*)(((rx_buffer_st*)buf)->ptr) + offset)[0],
																					(char*)((char*)(((rx_buffer_st*)buf)->ptr) + offset)[1],
																					(char*)((char*)(((rx_buffer_st*)buf)->ptr) + offset)[2],
																					(char*)((char*)(((rx_buffer_st*)buf)->ptr) + offset)[3],
																					(char*)((char*)(((rx_buffer_st*)buf)->ptr) + offset)[4],
																					(char*)((char*)(((rx_buffer_st*)buf)->ptr) + offset)[5],
																					(char*)((char*)(((rx_buffer_st*)buf)->ptr) + offset)[6],
																					(char*)((char*)(((rx_buffer_st*)buf)->ptr) + offset)[7]));
		pSpiDevExt->pBD_ReadCBFunc(pSpiDevExt->hBDContext, (char*)(((rx_buffer_st*)buf)->ptr) + offset, (DWORD)len);
#ifdef MEASURE_PERFORMANCE
		g_RecievedBytes += len;
#endif
	}
	DBGMSG(ZONE_INFO, (TEXT("SmsSpi: MsgFound end.\r\n")));
	
}

#ifdef MEASURE_PERFORMANCE
static void performanceMeasureTask(PVOID pArg)
{
	PSPIDEVICEEXTENSION pSpiDevExt  = (PSPIDEVICEEXTENSION)pArg;
	DWORD startTime = GetTickCount();
	DWORD testPeriod = 0;
	g_RecievedBytes = 0;

	while (1)
	{
		Sleep(1000);
		DBGMSG(ZONE_ERROR, (TEXT("SmsSpi: Current performance %d KB/Sec.\r\n"),g_RecievedBytes / (GetTickCount() - startTime)));
		testPeriod++;
		if (testPeriod >=30)
		{
			startTime = GetTickCount();
			g_RecievedBytes = 0;
		}


	}
}
#endif

static void smsspi_interruptHandler(PVOID pArg)
{
	PSPIDEVICEEXTENSION pSpiDevExt  = (PSPIDEVICEEXTENSION)pArg;
	DBGMSG(ZONE_INFO, (TEXT("SmsSpi: Interrupt().\r\n")));
	SetEvent(pSpiDevExt->transferMsgQueue);
}


static VOID SpiTransferThread(PVOID pArg)
{
	PSPIDEVICEEXTENSION pSpiDevExt  = (PSPIDEVICEEXTENSION)pArg;
	struct spi_msg *msg;

	while (1)
	{
		WaitForSingleObject(pSpiDevExt->transferMsgQueue, INFINITE);
		DBGMSG(ZONE_DETAILED, (TEXT("SmsSpi: Recieved xfer event.\r\n")));
		msg = (struct spi_msg *)GetEventData(pSpiDevExt->transferMsgQueue);
		if (msg)
		{
			DBGMSG(ZONE_INFO, (TEXT("SmsSpi: Transfering packet, buf=0x%x, len=%d.\r\n"), msg->buf, msg->len));
			SetEventData(pSpiDevExt->transferMsgQueue, 0);
		}
		smsspi_common_transfer_msg(&pSpiDevExt->dev, msg, pSpiDevExt->PaddingAllowed);
        SetEvent(pSpiDevExt->WriteOperation);
		DBGMSG(ZONE_DETAILED, (TEXT("SmsSpi: End xfer event.\r\n")));
    }

}

static rx_buffer_st* allocate_rx_buf(void* context, int size)
{
	PSPIDEVICEEXTENSION pSpiDevExt = (PSPIDEVICEEXTENSION)context;
	if (size <= RX_BUF_SIZE)
	{
		return &pSpiDevExt->rxbuf;
	}
	else
		return NULL;
}

static void free_rx_buf (void* Context, rx_buffer_st* buf)
{
}

/*************************************************************************************
FUNCTION NAME:	GetInstance

DESCRIPTION:	getting the instancenum and name from the registry

*************************************************************************************/
DWORD GetInstance(WCHAR *szName)
{
	HKEY hSpikey;
	LONG lRes;
	DWORD dwType;
	DWORD CurrInstancenum;
	DWORD DataSize;
	
	lRes = RegOpenKeyEx( 
						HKEY_LOCAL_MACHINE, 
						REG_PATH, 
						0,//N\A 
						0,//N\A
						 &hSpikey 
						);
	if(lRes != ERROR_SUCCESS)
		return (-1);

	DataSize=sizeof(DWORD);
	lRes = RegQueryValueEx( 
						  hSpikey, 
						  L"MiniPortInstance", 
						  0, 
						  &dwType, 
						  (LPBYTE)&CurrInstancenum, 
						  &DataSize 
						); 
	if(lRes!=ERROR_SUCCESS)	
	{
		RegCloseKey(hSpikey);
		return (-1);
	}
	
	DataSize=MAX_MNPRT_NAME;
	lRes = RegQueryValueEx( 
						  hSpikey, 
						  L"MiniportName", 
						  0, 
						  &dwType, 
						  (LPBYTE)szName, 
						  &DataSize 
						); 
	if(lRes!=ERROR_SUCCESS)	
	{
		RegCloseKey(hSpikey);
		return (-1);
	}

	RegCloseKey(hSpikey);
	return CurrInstancenum;
}




/*************************************************************************************
						Driver Actual Implementation 
				  --------------------------------------
*************************************************************************************/
/*************************************************************************************
FUNCTION NAME:	DllEntry

DESCRIPTION:	Standard DLLEntry point for a DLL

PARAMETERS:		[IN]	HANDLE	hDllHandle	-	Instance to dll module 
				[IN]	DWORD	dwReasone	-	Reasone for the calling the routine 
				[IN]	LPVOID	lpReserved	-	Reserved	
										   
RETURN VALUE:	None

REMARKS			NONE
*************************************************************************************/
BOOL WINAPI DllEntry(
   HANDLE hDllHandle, 
   DWORD  dwReason, 
   LPVOID lpreserved
   ) 
{
    BOOL bRc = TRUE;
    
    UNREFERENCED_PARAMETER(hDllHandle);
    UNREFERENCED_PARAMETER(lpreserved);
    
    switch (dwReason) {
        case DLL_PROCESS_ATTACH: 
			{
            DEBUGREGISTER((HINSTANCE)hDllHandle);
            DEBUGMSG(1,(_T("***SMS_SPI DLL_PROCESS_ATTACH - Current Process: 0x%x, ID: 0x%x ***\r\n"),
                GetCurrentProcess(), GetCurrentProcessId()));
	
			
			} 
			break;
			
        case DLL_PROCESS_DETACH: 
			{
            DEBUGMSG(1,(_T("***SMS_SPI DLL_PROCESS_DETACH - Current Process: 0x%x, ID: 0x%x ***\r\n"),
                GetCurrentProcess(), GetCurrentProcessId()));


			} 
			break;
			
        default:
            break;
    }
	
    return bRc;
}


static VOID FreeAllocatedResources(PSPIDEVICEEXTENSION pSpiDevExt)
{
	DMA_ADAPTER_OBJECT adapter;

	if (pSpiDevExt)
	{
		pSpiDevExt->pBD_ReadCBFunc = NULL;
		Sleep(1); // Make sure the MsgFound finish before removing GenDrv to avoid race condition.
		if (pSpiDevExt->hSmsGenDrv != INVALID_HANDLE_VALUE)
		{
			DeactivateDevice(pSpiDevExt->hSmsGenDrv);
			pSpiDevExt->hSmsGenDrv = INVALID_HANDLE_VALUE;
		}
		if (pSpiDevExt->transferThread)
		{
			TerminateThread(pSpiDevExt->transferThread, 0);
			CloseHandle(pSpiDevExt->transferThread);
		}
		if (pSpiDevExt->performanceThread)
		{
			TerminateThread(pSpiDevExt->performanceThread, 0);
			CloseHandle(pSpiDevExt->performanceThread);
		}
		if (pSpiDevExt->transferMsgQueue)
		{
			CloseHandle(pSpiDevExt->transferMsgQueue);
		}
		if (pSpiDevExt->WriteOperation)
		{
			CloseHandle(pSpiDevExt->WriteOperation);
		}

		if (pSpiDevExt->dev.rxbuf)
		{
			LocalFree(pSpiDevExt->dev.rxbuf);
		}
		if (pSpiDevExt->phyDrv)
		{
			smsspiphy_deinit(pSpiDevExt->phyDrv);
			pSpiDevExt->phyDrv = NULL;
		}
		if (pSpiDevExt->txbuf)
		{
			PHYSICAL_ADDRESS phyAddr;
			phyAddr.QuadPart = pSpiDevExt->txbuf_phy_addr;
			HalFreeCommonBuffer(&adapter, TX_BUF_SIZE, phyAddr, pSpiDevExt->txbuf, FALSE);
		}
		if (pSpiDevExt->rxbuf.ptr)
		{
			PHYSICAL_ADDRESS phyAddr;
			phyAddr.QuadPart = pSpiDevExt->rxbuf.phy_addr;
			HalFreeCommonBuffer(&adapter, TX_BUF_SIZE, phyAddr, pSpiDevExt->rxbuf.ptr, FALSE);
		}
		LocalFree(pSpiDevExt);
		pSpiDevExt = NULL;
	}
}

static BOOL GetRegistrySettings(PVOID Context, PSPIDEVICEEXTENSION pSpiDevExt )
{
	TCHAR*	regKey;
	BOOL	st;
	HKEY	hKey;
	DWORD	dataSize, type;
	SPI_DEVICE_TYPE_E	deviceType;

	regKey = (TCHAR *)LocalAlloc (LPTR, MAX_REG_KEY_SIZE);
	if (regKey == NULL)
	{
		DBGMSG( ZONE_ERROR,(TEXT("Siano SPI - ERROR!! Allocating memory for registry reading failed.\r\n")));
		return FALSE;
	}


	st = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCWSTR)Context, 0, 0, &hKey);						
	if(st != ERROR_SUCCESS)
	{
		DBGMSG( ZONE_ERROR,(TEXT("Siano SPI - ERROR!! Could not open registry key.\r\n")));
		LocalFree(regKey);
		return (FALSE);
	}

	dataSize=MAX_REG_KEY_SIZE;
	st = RegQueryValueEx(	hKey, 
							TEXT("Key"), 
							NULL,
							&type, 
							(LPBYTE)regKey, 
							&dataSize);
	
	RegCloseKey(hKey);
	if(st!=ERROR_SUCCESS)	
	{
		DBGMSG( ZONE_ERROR,(TEXT("Siano SPI - ERROR!! Could not get registry key name.\r\n")));
		LocalFree(regKey);
		return (FALSE);
	}
	
	// Now - read all the needed parameters for the driver from the registry.


	st = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regKey, 0, 0, &hKey);
	if(st != ERROR_SUCCESS)
	{
		DBGMSG( ZONE_ERROR,(TEXT("Siano SPI - ERROR!! Could not open registry key.\r\n")));
		LocalFree(regKey);
		return (FALSE);
	}

	dataSize = sizeof(deviceType);
	st = RegQueryValueEx( hKey, 
					  L"DeviceType", 
					  0, 
					  &type, 
					  (LPBYTE)&deviceType, 
					  &dataSize);

	if(st != ERROR_SUCCESS)
	{ //Set default value if registry entry is not found.

		DBGMSG( ZONE_ERROR,(TEXT("[ERR]CMMB Module select error, should be vega.\r\n")));
		deviceType = SPI_DEVICE_STELLAR;
	}

	switch(deviceType)
	{
		case SPI_DEVICE_NOVA:
			pSpiDevExt->bdType = BD_TYPE_SPI_NOVA;
			break;
		case SPI_DEVICE_VEGA:
			pSpiDevExt->bdType = BD_TYPE_SPI_VEGA;
			break;
		default:
			pSpiDevExt->bdType = BD_TYPE_SPI_STELLAR;
			break;
	}

	st = RegCloseKey(hKey);
	if(st!=ERROR_SUCCESS)	
	{
		DBGMSG( ZONE_ERROR,(TEXT("Siano SPI - ERROR!! Could not get registry key name.\r\n")));
		LocalFree(regKey);
		return (FALSE);
	}

	LocalFree(regKey);
	return (TRUE);

}

/*************************************************************************************
FUNCTION NAME:	SPI_Init

DESCRIPTION:	Streame Driver Init entry point

PARAMETERS:		[IN]	Context - pointer to the registry path for the device's parameters.
										   
RETURN VALUE:	None

REMARKS			NONE
*************************************************************************************/
DWORD WINAPI SPI_Init(PVOID Context)
{

	DWORD Res = 0;
	DMA_ADAPTER_OBJECT adapter;
	MSGQUEUEOPTIONS	msgOptions;
	PHYSICAL_ADDRESS phyAddr;
	PSPIDEVICEEXTENSION pSpiDevExt = (PSPIDEVICEEXTENSION)LocalAlloc(LPTR,sizeof(SPIDEVICEEXTENSION));
	spi_dev_cb_st cbParams;
	
	DBGMSG(1, (TEXT("SmsSpi: SPI_Init() Start.\r\n")));

	if(pSpiDevExt == NULL)
	{
		DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("SmsSpi: SPI_Init() failed to allocate memory for handle.\r\n")));
		return 0;
	}

	memset (pSpiDevExt, 0, sizeof(SPIDEVICEEXTENSION));

	//Init the hw:
	

	
	pSpiDevExt->txbuf = HalAllocateCommonBuffer(&adapter, TX_BUF_SIZE, &phyAddr, FALSE);
	pSpiDevExt->txbuf_phy_addr = phyAddr.LowPart;
	pSpiDevExt->rxbuf.ptr = HalAllocateCommonBuffer(&adapter, RX_BUF_SIZE, &phyAddr, FALSE);
	pSpiDevExt->rxbuf.phy_addr = phyAddr.LowPart;
	pSpiDevExt->PaddingAllowed = 1;
	pSpiDevExt->pBD_ReadCBFunc = NULL;

	GetRegistrySettings(Context, pSpiDevExt);

	pSpiDevExt->phyDrv = smsspiphy_init((void*)Context, smsspi_interruptHandler, pSpiDevExt);
	if (pSpiDevExt->phyDrv == NULL)
	{
		DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("SmsSpi: SPI_Init() failed to initialize physical driver.\r\n")));
		FreeAllocatedResources(pSpiDevExt);
		return 0;
	}
	pSpiDevExt->dev.rxbuf = LocalAlloc(LPTR, RX_BUF_SIZE);
	if (pSpiDevExt->dev.rxbuf == NULL)
	{
		DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("SmsSpi: SPI_Init() failed to allocate memory for RX buffer.\r\n")));
		FreeAllocatedResources(pSpiDevExt);
		return 0;
	}

	cbParams.transfer_data_cb = smsspibus_xfer;
	cbParams.msg_found_cb = MsgFound;
	cbParams.allocate_rx_buf = allocate_rx_buf;
	cbParams.free_rx_buf = free_rx_buf;
	smsspicommon_init(&pSpiDevExt->dev, pSpiDevExt, pSpiDevExt->phyDrv, &cbParams);

	memcpy (pSpiDevExt->txbuf, preamble_pattern, sizeof(preamble_pattern));
	


	pSpiDevExt->WriteOperation = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (pSpiDevExt->WriteOperation == NULL)
	{
		DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("SmsSpi: SPI_Init() failed to create Write event.\r\n")));
		FreeAllocatedResources(pSpiDevExt);
		return 0;
	}

	msgOptions.dwSize = sizeof(msgOptions);
	msgOptions.dwFlags = 0;
	msgOptions.dwMaxMessages = 5;
	msgOptions.cbMaxMessage = sizeof(struct spi_msg);
	msgOptions.bReadAccess = TRUE;

	pSpiDevExt->transferMsgQueue = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (pSpiDevExt->transferMsgQueue == NULL)
	{
		DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("SmsSpi: SPI_Init() failed to create transferMsgQueue.\r\n")));
		FreeAllocatedResources(pSpiDevExt);
		return 0;
	}

	pSpiDevExt->transferThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)SpiTransferThread, pSpiDevExt, 0, NULL);
	if (pSpiDevExt->transferThread == NULL)
	{
		DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("SmsSpi: SPI_Init() failed to create transferThread thread.\r\n")));
		FreeAllocatedResources(pSpiDevExt);
		return 0;
	}
	if (CeSetThreadPriority(pSpiDevExt->transferThread, 100) == FALSE)
	{
		DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("SmsSpi: SPI_Init() failed to set transferThread thread priority.\r\n")));
		FreeAllocatedResources(pSpiDevExt);
		return 0;
	}
#ifdef MEASURE_PERFORMANCE
	pSpiDevExt->performanceThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)performanceMeasureTask, pSpiDevExt, 0, NULL);
#endif
	

	pSpiDevExt->hSmsGenDrv = ActivateDevice(SMS_GEN_DRIVER_REGISTRY_PATH,pSpiDevExt->bdType);

	if (pSpiDevExt->hSmsGenDrv == NULL || pSpiDevExt->hSmsGenDrv == INVALID_HANDLE_VALUE)
	{
		DBGMSG(ZONE_ERROR, (TEXT("SmsSpi: Failed to load SmsGenDrv. Error %d\r\n"),GetLastError()));
		FreeAllocatedResources(pSpiDevExt);
		return 0;
	}
	

	return (DWORD)pSpiDevExt;
}
    
/*************************************************************************************
FUNCTION NAME:	SPI_Deinit

DESCRIPTION:	Streame Driver Deinit entry point

PARAMETERS:		[IN]	Context - N/A
										   
RETURN VALUE:	None

REMARKS			NONE
EXAMPLES		NONE
*************************************************************************************/
BOOL WINAPI SPI_Deinit(DWORD dwContext)
{
	PSPIDEVICEEXTENSION pSpiDevExt = (PSPIDEVICEEXTENSION)dwContext;

	FreeAllocatedResources(pSpiDevExt);
	return TRUE;
}


/*************************************************************************************
FUNCTION NAME:	SPI_Open

DESCRIPTION:	Streame Driver Open entry point

PARAMETERS:		[IN]	Context   - 
				[IN]	Access	  -	N/A.
				[IN]	ShareMode -  N/A.
										   
RETURN VALUE:	None

REMARKS			NONE
*************************************************************************************/
DWORD WINAPI SPI_Open(
						DWORD Context, 
						DWORD Access,
						DWORD ShareMode)
{

	DBGMSG(ZONE_INFO, (TEXT("SmsSpi: SPI_Open()\r\n")));
	return (DWORD)Context;

}


/*************************************************************************************
FUNCTION NAME:	SPI_Close

DESCRIPTION:	Streame Driver Close entry point

PARAMETERS:		[IN]	Context   - 
				[IN]	Access	  -	N/A.
				[IN]	ShareMode -  N/A.
										   
RETURN VALUE:	None

REMARKS			NONE
*************************************************************************************/
BOOL WINAPI SPI_Close(DWORD Context) 
{
	DBGMSG(ZONE_INFO, (TEXT("SmsSpi: SPI_Close()\r\n")));
	
	return TRUE;
}


/*************************************************************************************
FUNCTION NAME:	SPI_Read

DESCRIPTION:	Streame Driver Read entry point

PARAMETERS:		[IN]	DWORD  dwContext   - 
				[IN]	LPVOID pBuffer - User input buffer.
				[IN]	DWORD  BufferLength
										   
RETURN VALUE:	None

REMARKS			NONE

*************************************************************************************/
DWORD WINAPI SPI_Read(DWORD  dwContext, LPVOID pBuffer, DWORD  BufferLength) 
{
	DBGMSG(ZONE_ERROR, (TEXT("SmsSpi: SPI_Read() called, but not supported\r\n")));
	return (-1);
}

/*************************************************************************************
FUNCTION NAME:	SPI_Write

DESCRIPTION:	Streame Driver Write entry point

PARAMETERS:		[IN]	DWORD  dwContext  
				[IN]	LPVOID pBuffer - User input buffer.
				[IN]	DWORD  BufferLength
										   
RETURN VALUE:	None

REMARKS			NONE
*************************************************************************************/
DWORD WINAPI SPI_Write(DWORD  dwContext, LPVOID pBuff, DWORD  BufferLength) 
{	
	int 	Cnt;
	int 	AddingPreamble, WrittenBytes;
	static struct spi_msg   txmsg;
	PSPIDEVICEEXTENSION pSpiDevExt  = (PSPIDEVICEEXTENSION)dwContext;
	
	DBGMSG(ZONE_INFO, (TEXT("SmsSpi: SPI_Write() Writing %d bytes.\r\n"), BufferLength));

	AddingPreamble = 1;
	if (BufferLength > 0x1000)
	{ /* The FW is the only long message. Do not add preamble, and do not padd it*/
		pSpiDevExt->PaddingAllowed = 0;
		AddingPreamble = 0;
		BufferLength += 4;
		smschipreset(pSpiDevExt->phyDrv);		
	}
	WrittenBytes = 0;
		
	while (BufferLength > 0)
	{
		ResetEvent(pSpiDevExt->WriteOperation);	
		txmsg.buf = pSpiDevExt->txbuf;
		txmsg.buf_phy_addr = pSpiDevExt->txbuf_phy_addr;
		if (AddingPreamble == 1)
		{
			DBGMSG(ZONE_INFO, (TEXT("SmsSpi: SPI_Write() Adding peamble.\r\n")));
			Cnt = min((int)(BufferLength + sizeof(preamble_pattern)), (int)TX_BUF_SIZE);
			txmsg.len = Cnt;
			memcpy (pSpiDevExt->txbuf, preamble_pattern, sizeof(preamble_pattern));
			memcpy(pSpiDevExt->txbuf+sizeof(preamble_pattern), pBuff, Cnt - sizeof(preamble_pattern));
			WrittenBytes += (Cnt - sizeof(preamble_pattern));
			BufferLength -= (Cnt - sizeof(preamble_pattern));		
		}
		else
		{
			DBGMSG(ZONE_INFO, (TEXT("SmsSpi: SPI_Write() No preamble added.\r\n")));
			Cnt = min(BufferLength, TX_BUF_SIZE);
			txmsg.len = Cnt;
			memcpy(pSpiDevExt->txbuf, (CHAR*)pBuff, Cnt);
			WrittenBytes += Cnt;
			BufferLength -= Cnt;		
		}
		memset (pSpiDevExt->txbuf + Cnt, 0, TX_BUF_SIZE - Cnt);
		DBGMSG(ZONE_INFO, (TEXT("SmsSpi: SPI_Write() Sending to transfer queue. buf = 0x%x, len=%d.\r\n"), txmsg.buf, txmsg.len));
		SetEventData(pSpiDevExt->transferMsgQueue, (DWORD)&txmsg);
		DBGMSG(ZONE_INFO, (TEXT("SmsSpi: SPI_Write() Sending to transfer queue. msg = 0x%x.\r\n"), (DWORD)&txmsg));
		SetEvent(pSpiDevExt->transferMsgQueue);
		WaitForSingleObject(pSpiDevExt->WriteOperation, INFINITE);
		memset (pSpiDevExt->txbuf, 0, Cnt);
		(PCHAR)pBuff+=Cnt;		
		AddingPreamble = 0;
	}
	pSpiDevExt->PaddingAllowed = 1;
	DBGMSG(ZONE_INFO, (TEXT("SmsSpi: SPI_Write() Write exits.\r\n")));
	return WrittenBytes;
	
}

/*************************************************************************************
FUNCTION NAME:	SPI_IOControl

DESCRIPTION:	Streame Driver IOControl entry point

PARAMETERS:		[IN]	DWORD  dwContext - 
				[IN]	DWORD  Ioctl - Command
				[IN]	PUCHAR pInBuf - Input Buffer
				[IN]	DWORD  InBufLen - Input Buffer Length 
				[IN]	PUCHAR pOutBuf - Output Buffer
				[IN]	DWORD  OutBufLen - Output Buffer Length
				[IN]	PDWORD pdwBytesTransferred - Bytes Transfferd.
										   
RETURN VALUE:	None

REMARKS			NONE
*************************************************************************************/
BOOL WINAPI SPI_IOControl(
    DWORD  dwContext,
    DWORD  Ioctl,
    PUCHAR pInBuf,
    DWORD  InBufLen, 
    PUCHAR pOutBuf,
    DWORD  OutBufLen,
    PDWORD pdwBytesTransferred
   )
{	
	BOOL retVal;
	PSPIDEVICEEXTENSION pSpiDevExt  = (PSPIDEVICEEXTENSION)dwContext;

	retVal = FALSE;

	switch(Ioctl)
	{
		case SIANO_BD_IOCTL_REGISTER_READ_CB:
			if ((pInBuf != NULL) && (InBufLen >= sizeof(BD_IOCTL_REGISTER_READ_PARAMS_ST)))
			{
				pSpiDevExt->hBDContext = ((PBD_IOCTL_REGISTER_READ_PARAMS_ST)pInBuf)->hContext;
				pSpiDevExt->pBD_ReadCBFunc = ((PBD_IOCTL_REGISTER_READ_PARAMS_ST)pInBuf)->pBD_ReadCBFunc;
				retVal = TRUE;
			}
			break;

		case SIANO_BD_IOCTL_WRITE_FW_BUFF_TO_DEVICE:
			if ((pInBuf != NULL) && (InBufLen >= sizeof(BD_IOCTL_DOWNLOAD_FW_ST)))
			{
				WriteFWtoStellar(pSpiDevExt->phyDrv,((PBD_IOCTL_DOWNLOAD_FW_ST)pInBuf)->buf,((PBD_IOCTL_DOWNLOAD_FW_ST)pInBuf)->size);
				retVal = TRUE;
			}
			break;
        case SIANO_BD_IOCTL_PREPARE_FOR_FW_DNL: 
            prepareForFWDnl(pSpiDevExt->phyDrv);
            retVal = TRUE;
            break;
        case SIANO_BD_IOCTL_FW_DNL_COMPLETE:
            fwDnlComplete(pSpiDevExt->phyDrv);
            retVal = TRUE;
            break;


		case IOCTL_POWER_CAPABILITIES:
			DBGMSG(ZONE_INFO, (TEXT("SmsSpi: IOCTL_POWER_CAPABILITIES - supported power states are D0, D3 and D4\r\n")));
			if (pOutBuf != NULL && pdwBytesTransferred != NULL && OutBufLen >= sizeof(POWER_CAPABILITIES))
			{
				PPOWER_CAPABILITIES pCapabilities = (PPOWER_CAPABILITIES)pOutBuf;
				memset(pCapabilities, 0, sizeof(POWER_CAPABILITIES));
				// support D0, D3, D4
				pCapabilities->DeviceDx = DX_MASK(D0)|DX_MASK(D3)|DX_MASK(D4);
				*pdwBytesTransferred = sizeof(POWER_CAPABILITIES);
				retVal = TRUE;
				break;
			}
			
		case IOCTL_POWER_SET:
			DBGMSG(ZONE_INFO, (TEXT("SmsSpi: IOCTL_POWER_SET - Changing power state to 0x%x \r\n"),*(CEDEVICE_POWER_STATE*)pOutBuf));
			/* Here we need to send the command of changing the power state to FW - not supported yet*/
			if (pSpiDevExt->powerState >= D3 && *(CEDEVICE_POWER_STATE*)pOutBuf == D0)
			{ // When going back to D0 need to reset the FW in  order to make sure the device is ready for FW download.
				Sleep(1000);
			}
			pSpiDevExt->powerState = *(CEDEVICE_POWER_STATE*)pOutBuf;
			retVal = TRUE;
			break;
		case IOCTL_POWER_GET:
			DBGMSG(ZONE_INFO, (TEXT("SmsSpi: IOCTL_POWER_GET - power state is 0x%x \r\n"),pSpiDevExt->powerState));
			*(CEDEVICE_POWER_STATE*)pOutBuf = pSpiDevExt->powerState;
			retVal = TRUE;
			break;
		case IOCTL_REGISTER_POWER_RELATIONSHIP:			
			DBGMSG(ZONE_WARNING, (TEXT("SmsSpi: Power manager command - not supported yet 0x%x \r\n"),Ioctl));
			break;
		case IOCTL_POWER_QUERY:
			DBGMSG(ZONE_INFO, (TEXT("SmsSpi: IOCTL_POWER_QUERY - not supported yet 0x%x \r\n"),Ioctl));
			if (*(CEDEVICE_POWER_STATE*)pOutBuf == D3) //D3 is not supported by SMS1000
				*(CEDEVICE_POWER_STATE*)pOutBuf = PwrDeviceUnspecified;
			retVal = TRUE;
			break;

        default:
            break;
	}

	return retVal;

}


/*************************************************************************************
FUNCTION NAME:	SPI_Seek

DESCRIPTION:	Streame Driver Seek entry point

PARAMETERS:		[IN]	DWORD  dwContext   - 
				[IN]	LONG Position.
				[IN]	DWORD  Type
										   
RETURN VALUE:	None

REMARKS			Not implemented for this device
*************************************************************************************/
ULONG SPI_Seek(
   PVOID Context,
   LONG  Position,
   DWORD Type
   )
{
    UNREFERENCED_PARAMETER(Context);
    UNREFERENCED_PARAMETER(Position);
    UNREFERENCED_PARAMETER(Type);
    
    return (ULONG)-1;
}


/*************************************************************************************
FUNCTION NAME:	SPI_PowerDown

DESCRIPTION:	PowerDown entry point

PARAMETERS:		[IN]	DWORD  dwContext   - pointer to a USBGEN_CONTEXT sructure.
				
										   
RETURN VALUE:	None

REMARKS			Not implemented for this device
*************************************************************************************/
VOID WINAPI SPI_PowerDown(DWORD dwContext)
{
	UNREFERENCED_PARAMETER(dwContext);
}


/*************************************************************************************
FUNCTION NAME:	SPI_PowerUp

DESCRIPTION:	PowerUp entry point

PARAMETERS:		[IN]	DWORD  dwContext   - pointer to a USBGEN_CONTEXT sructure.
				
										   
RETURN VALUE:	None

REMARKS			Not implemented for this device
*************************************************************************************/
VOID WINAPI SPI_PowerUp(DWORD dwContext)
{
	UNREFERENCED_PARAMETER(dwContext);
	
}



